/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.web.Interceptor;


import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONObject;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.json.utils.JsonUtils;
import com.comac.ins.common.security.domain.SsoUser;
import com.comac.ins.common.security.utils.CookieUtil;
import com.comac.ins.system.domain.vo.SysClientVo;
import com.comac.ins.system.domain.vo.SysUserVo;
import com.comac.ins.system.service.ISysClientService;
import com.comac.ins.web.domain.vo.LoginVo;
import com.comac.ins.web.service.IAuthStrategy;
import com.comac.ins.web.service.SysLoginService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {

    private final static String SSO_SESSION_ID = "xxl_sso_sessionid";
    private final static String SSO_USER = "xxl_sso_user";

    @Value("${xxl.sso.authUrl}")
    private String sso_server;

    @Value("#{T(java.lang.Boolean).parseBoolean('${xxl.sso.enable}')}")
    private Boolean sso_enable;

    @Value("${isfd.nopassword.clientId}")
    private String clientId;
    private final String grantType = "nopassword";

    @Autowired
    private RestTemplate tokenRestTemplate;

    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysClientService clientService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!sso_enable) {
            return true;
        }

        String token = StpUtil.getTokenValue();

        // 1.从cookie、请求参数、header里获取xxl_sso_sessionid
        String cookieSessionId = CookieUtil.getValue(request, SSO_SESSION_ID);
        if (StringUtils.isBlank(cookieSessionId)) {
            cookieSessionId = request.getParameter(SSO_SESSION_ID);
            if (StringUtils.isBlank(cookieSessionId)) {
                cookieSessionId = request.getHeader(SSO_SESSION_ID);
            }
        }
        if (StringUtils.isEmpty(cookieSessionId)) {
            StpUtil.logout();
            throw new BaseException("获取cookieSessionId失败！");
        }
        String storeKey = CookieUtil.parseStoreKey(cookieSessionId);
        if (StringUtils.isEmpty(storeKey)) {
            StpUtil.logout();
            throw new BaseException("获取storeKey失败！");
        }
        String cacheKey = cacheKey(storeKey);
        Map<String, String> param = new HashMap<>();
        param.put("cacheKey", cacheKey);
        // 2. 调用sso
        ResponseEntity<JSONObject> responseEntity = tokenRestTemplate.postForEntity(sso_server, param, JSONObject.class);
        JSONObject body = responseEntity.getBody();

        if (ObjectUtils.isEmpty(body) || body.getInt("code") != 0) {
            log.error("调用统一认证中心服务失败 sso_server is {} , param is {} ", sso_server, param);
            StpUtil.logout();
            throw new BaseException("调用统一认证中心服务失败！");
        }
        String result = JsonUtils.toJsonString(body.getJSONObject("data").getJSONObject("cacheValueObj"));
        if (result == null) {
            log.error("调用统一认证中心服务获取user失败, sso_server is {} , param is {} ", sso_server, param);
            StpUtil.logout();
            throw new BaseException("调用统一认证中心服务获取user失败！");
        }
        // 3.判断sso用户和本地用户关联关系
        SsoUser user = JsonUtils.parseObject(result, SsoUser.class);
        String employeeCode = user.getEmployeeCode();
//        String employeeCode = "500695";
        SysUserVo sysUserVo = loginService.getUserByUserName(employeeCode);
        if (sysUserVo == null) {
            StpUtil.logout();
            throw new BaseException("业务系统用户不存在，请关联用户后重试！");
        }
        Long userId = sysUserVo.getUserId();
        // 4. 判断token是否失效，失效的话需要激活
        Object loginIdByToken = null;
        try {
            loginIdByToken = StpUtil.getLoginId();
        } catch (Exception e) {
            log.error("token失效，需要重新登录！", e);
        }

        if (loginIdByToken != null) {
            String loginIds = (String) loginIdByToken;
            String loginId = loginIds.split(":")[1];
            if (!String.valueOf(userId).equals(loginId)) {
                StpUtil.logout();
                throw new BaseException("统一认证中心用户未登录，已退出！");
            }
        } else {
            JSONObject loginBodyJson = new JSONObject();
            loginBodyJson.set("tenantId", sysUserVo.getTenantId());
            loginBodyJson.set("username", sysUserVo.getUserName());
            loginBodyJson.set("rememberMe", Boolean.TRUE);
            loginBodyJson.set("clientId", clientId);
            loginBodyJson.set("grantType", grantType);
            String loginBodyJsonStr = loginBodyJson.toString();
            SysClientVo client = clientService.queryByClientId(clientId);
            // 5. 登录后，重新设置token到response头部
            LoginVo loginVo = IAuthStrategy.login(loginBodyJsonStr, client, grantType);
            token = loginVo.getAccessToken();
        }
        CookieUtil.setSsoUser(user);
        request.setAttribute(SSO_USER, user);
        response.setHeader("Isfd-Token", token);
        response.setHeader(SSO_USER, JsonUtils.toJsonString(user));
        return true;
    }

    private String cacheKey(String sessionId) {
        return SSO_SESSION_ID.concat("#").concat(sessionId);
    }
}
